#include "updater.h"
#include <qDebug>
Updater::Updater(QObject *parent) : QObject(parent) {
  //数据packer
  upacker = new Upacker();
  connect(upacker, SIGNAL(recvPack(QByteArray)), this,
          SLOT(packHandler(QByteArray)));
  update_worker.index_list = NULL;
  //
  timer = new QTimer(this);
  timer->setSingleShot(true);
  connect(timer, SIGNAL(timeout()), this, SLOT(updateCaption()));
}

void Updater::packHandler(QByteArray data) {
  int size = data.length();
  char *pdata = data.data();
  if (size < 2) {
    qDebug() << "error frame recived";
    return;
  }
  uint16_t cmd = *(uint16_t *)pdata;
  if (cmd == CMD_DOWN_REPLY) {
    //下载固件的起始指令，后接updater_header
    //手动赋值
    uint32_t *pcmd = (uint32_t *)(pdata + 2);
    stopTimer();
    //发送第一个数据包
    sendFirstPack();
    emit downloadRunning();
    qDebug() << "updater header is acked! start download";
  } else if (cmd == CMD_CTL_REPLY) {
    //控制指令
  } else if (cmd == CMD_PACK_REPLY) {
    uint16_t index = *(uint16_t *)(pdata + 2);
    update_worker.index_win++;
    setIndexStatus(index, 1);
    ////
    setProgress((float)(update_worker.index_win + update_worker.index_cur) *
                1.0 / (float)update_header.fw_pack_num);
    emit downloadProgress(index, progress * 100);
    qDebug() << "download ack, pack number:" << index;

    //每8个包作为一个区块，按区块做检查是否下载完整
    if (update_worker.index_win < 8) {
      sendPack(update_worker.index_win + update_worker.index_cur);
    } else {
      //检查区块是否完整
      uint8_t block = getIndexBlock(index);
      if (block != 0xff) {
        for (int i = 0; i < 8; i++) {
          if ((block & (1 << i)) < 1) {
            sendPack(update_worker.index_cur + i);
            break;
          }
        }
      } else {
        update_worker.index_cur += 8;
        update_worker.index_win = 0;
        //检查是否下载结束
        if (update_worker.index_cur == update_header.fw_pack_num) {
          //结束
          stopTimer();
          emit downloadComplete();
        } else {
          sendPack(update_worker.index_cur);
          //          sendPack(update_worker.index_cur + 1);
        }
      }
    }
  }
}

void Updater::unpackData(QByteArray data) { upacker->upacker_unpack(data); }

/**
 * @brief Updater::updateCaption
 * timer 超时回调
 *
 */
void Updater::updateCaption() {
  int userData = (int)timer->userData(1);
  if (userData == CMD_DOWN) {
    //下载header超时
    emit downReplyTimeout();
  } else if (userData == CMD_CTL) {
    emit ctlReplyTimeout();
  } else if (userData == CMD_PACK) {
    emit packReplyTimeout();
    //重试3次
    if (m_retry < 3) {
      //下载中途断开，考虑续传
      sendPack(update_worker.index_win);
    }
  }
  m_retry++;
}

void Updater::stopTimer() {
  m_retry = 0;
  timer->stop();
}

void Updater::setProgress(float value) {
  progress = value;
  emit progressChanged(progress);
}

bool Updater::getIndexStatus(int i) {
  return (update_worker.index_list[i / 8] & (1 << (i % 8))) > 0;
}

int Updater::getIndexBlock(int i) { return update_worker.index_list[i / 8]; }

bool Updater::setIndexStatus(int i, int v) {
  if (v > 0) {
    update_worker.index_list[i / 8] |= (1 << (i % 8));
  } else {
    update_worker.index_list[i / 8] &= ~(1 << (i % 8));
  }

  return true;
}

int32_t Updater::packSize() const { return m_packSize; }

void Updater::setPackSize(const int32_t &packSize) { m_packSize = packSize; }

/**
 * @brief Updater::sendUpdateHeader
 * 发送下载头部信息
 */
void Updater::sendUpdateHeader() {
  QByteArray buff;
  uint16_t cmd = CMD_DOWN;
  buff.append((const char *)&cmd, sizeof(cmd));
  buff.append((const char *)&update_header, sizeof(update_header));
  sendData(upacker->upacker_pack(buff));
}

void Updater::startDownload() {
  //初始化数据
  setProgress(0);
  //测速
  QTimer::singleShot(1000, this, SLOT(speedUpdate()));
  update_worker.index_list_len = update_header.fw_pack_num / 8;
  if (update_worker.index_list == NULL) {
    update_worker.index_list = (uint8_t *)malloc(update_worker.index_list_len);
  } else {
    update_worker.index_list = (uint8_t *)realloc(update_worker.index_list,
                                                  update_worker.index_list_len);
  }

  memset(update_worker.index_list, 0, update_worker.index_list_len);

  //按位计数，最后不足8位的提前补1；
  uint8_t diff_len = update_header.fw_pack_num % 8;
  for (int i = diff_len; i < 8; i++) {
    update_worker.index_list[update_worker.index_list_len - 1] |= 1 << i;
  }

  //发送下载头，需要等待回复
  sendUpdateHeader();
  //超时
  timer->setUserData(1, (QObjectUserData *)CMD_DOWN);
  timer->start(timeout);
}

void Updater::sendFirstPack() {
  update_worker.index_cur = 0;
  update_worker.index_win = 0;
  //直接传2个包
  sendPack(0);
  //  sendPack(1);
}

void Updater::sendPack(uint16_t index) {
  //重设
  timer->start(timeout);
  timer->setUserData(1, (QObjectUserData *)CMD_PACK);
  QByteArray buff;
  uint16_t cmd = CMD_PACK;
  buff.append((const char *)&cmd, sizeof(cmd));
  buff.append((const char *)&index, sizeof(index));
  buff.append(
      (const char *)(m_firmware.data() + index * update_header.fw_pack_size),
      update_header.fw_pack_size);
  sendData(upacker->upacker_pack(buff));
}

QByteArray Updater::firmware() const { return m_firmware; }

void Updater::setFirmware(QByteArray &firmware) {
  m_firmware = QByteArray(firmware.data(), firmware.length());
  int diff_len = m_packSize - firmware.size() % m_packSize;
  QByteArray diff;
  diff.resize(diff_len);
  diff.fill(0xff, diff_len);

  m_firmware.reserve(m_firmware.length() + diff_len);
  //把固件内容不足包长的补ff
  m_firmware.append(diff);
  update_header.ota_type = OTA_TYPE_DOWN;    // 固件的类型
  update_header.fw_size = firmware.length(); // 要下载的固件字节长度
  update_header.fw_pack_size = m_packSize;   //要下载的固件分包的包长
  update_header.fw_pack_num =                //要下载的固件分包的数量
      firmware.length() / m_packSize;

  qDebug() << "setFirmware, size:" << firmware.length()
           << " pack size:" << m_packSize
           << " pack num:" << update_header.fw_pack_num;
}
